#region File Description
//-----------------------------------------------------------------------------
// LobbyScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Net;
#endregion

namespace TankWars
{
    /// <summary>
    /// The lobby screen provides a place for gamers to congregate before starting
    /// the actual gameplay. It displays a list of all the gamers in the session,
    /// and indicates which ones are currently talking. Each gamer can press a button
    /// to mark themselves as ready: gameplay will begin after everyone has done this.
    /// </summary>
    class LobbyScreen : GameScreen
    {
        #region Fields

        NetworkSession networkSession;

        Texture2D isReadyTexture;
        Texture2D hasVoiceTexture;
        Texture2D isTalkingTexture;
        Texture2D voiceMutedTexture;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructs a new lobby screen.
        /// </summary>
        public LobbyScreen(NetworkSession networkSession)
        {
            this.networkSession = networkSession;

            TransitionOnTime = TimeSpan.FromSeconds(0.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);
        }


        /// <summary>
        /// Loads graphics content used by the lobby screen.
        /// </summary>
        public override void LoadContent()
        {
            ContentManager content = ScreenManager.Game.Content;

            isReadyTexture = content.Load<Texture2D>("ChatIcons/chat_ready");
            hasVoiceTexture = content.Load<Texture2D>("ChatIcons/chat_able");
            isTalkingTexture = content.Load<Texture2D>("ChatIcons/chat_talking");
            voiceMutedTexture = content.Load<Texture2D>("ChatIcons/chat_mute");
        }


        #endregion

        #region Update


        /// <summary>
        /// Updates the lobby screen.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            if (!IsExiting)
            {
                if (this.networkSession.SessionState == NetworkSessionState.Playing)
                {
                    // Leave the lobby and begin gameplay.
                    LoadingScreen.Load(ScreenManager, true, new NetworkGameplayScreen(networkSession));
                }
                else if (this.networkSession.IsHost && this.networkSession.IsEveryoneReady)
                {
                    // The host checks whether everyone has marked themselves
                    // as ready, and starts the game in response.
                    this.networkSession.StartGame();
                }
            }
        }


        /// <summary>
        /// Handles user input for all the local gamers in the session. Unlike most
        /// screens, which use the InputState class to combine input data from all
        /// gamepads, the lobby needs to individually mark specific players as ready,
        /// so it loops over all the local gamers and reads their inputs individually.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
            {
                PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex;

                if (input.IsMenuSelect(playerIndex) || (input.IsNewLeftClick() && gamer.IsLocal))
                {
                    HandleMenuSelect(gamer);
                }
                else if (input.IsMenuCancel(playerIndex) || (input.IsNewRightClick() && gamer.IsLocal))
                {
                    HandleMenuCancel(gamer);
                }
            }
        }


        /// <summary>
        /// Handle MenuSelect inputs by marking ourselves as ready.
        /// </summary>
        void HandleMenuSelect(LocalNetworkGamer gamer)
        {
            if (!gamer.IsReady)
            {
                gamer.IsReady = true;
            }
            else if (gamer.IsHost)
            {
                // The host has an option to force starting the game, even if not
                // everyone has marked themselves ready. If they press select twice
                // in a row, the first time marks the host ready, then the second
                // time we ask if they want to force start.
                MessageBoxScreen messageBox = new MessageBoxScreen("Confirm Force Start Game");

                messageBox.Accepted += ConfirmStartGameMessageBoxAccepted;

                ScreenManager.AddScreen(messageBox);
            }
        }


        /// <summary>
        /// Event handler for when the host selects ok on the "are you sure
        /// you want to start even though not everyone is ready" message box.
        /// </summary>
        void ConfirmStartGameMessageBoxAccepted(object sender, EventArgs e)
        {
            if (this.networkSession.SessionState == NetworkSessionState.Lobby)
            {
                this.networkSession.StartGame();
            }
        }


        /// <summary>
        /// Handle MenuCancel inputs by clearing our ready status, or if it is
        /// already clear, prompting if the user wants to leave the session.
        /// </summary>
        void HandleMenuCancel(LocalNetworkGamer gamer)
        {
            if (gamer.IsReady)
            {
                gamer.IsReady = false;
            }
            else
            {
                NetworkSessionComponent.LeaveSession(ScreenManager);
            }
        }


        #endregion

        #region Draw


        /// <summary>
        /// Draws the lobby screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont lobbyFont = ScreenManager.Font;

            // Start the x value to center screen and the y value to 30% from the top
            Vector2 position = new Vector2((ScreenManager.GraphicsDevice.Viewport.Width / 2),
                (float)(ScreenManager.GraphicsDevice.Viewport.Height * 0.3));

            // Make the lobby listing slide into place during transitions.
            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);

            // If transitioning, subtract from the final resting place
            if (ScreenState == ScreenState.TransitionOn)
                position.X -= transitionOffset * 256;

            spriteBatch.Begin();

            // Draw all the gamers in the session.
            foreach (NetworkGamer gamer in networkSession.AllGamers)
            {
                DrawGamer(gamer, position);

                // Advance to the next screen position
                position.Y += (float)ScreenManager.Font.LineSpacing * (float)1.75;
            }

            // Draw the menu title.
            string title = "Lobby";
            Vector2 titlePosition = new Vector2((ScreenManager.GraphicsDevice.Viewport.Width / 2), 80);
            Vector2 titleOrigin = lobbyFont.MeasureString(title) / 2;
            Color titleColor1 = new Color(255, 255, 255, TransitionAlpha);
            Color titleColor2 = new Color(0, 0, 0, TransitionAlpha);
            float titleScale = 1.75f;

            titlePosition.Y -= transitionOffset * 100;

            // Draw title in pseudo-3D form            
            spriteBatch.DrawString(lobbyFont, title, titlePosition + new Vector2(3), titleColor2, 0,
                                   titleOrigin, titleScale, SpriteEffects.None, 0);
            spriteBatch.DrawString(lobbyFont, title, titlePosition, titleColor1, 0,
                                   titleOrigin, titleScale, SpriteEffects.None, 0);

            spriteBatch.End();
        }


        /// <summary>
        /// Helper draws the gamertag and status icons for a single NetworkGamer.
        /// </summary>
        void DrawGamer(NetworkGamer gamer, Vector2 position)
        {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;
                        
            string text = gamer.Gamertag;
            if (gamer.IsHost)           // Add "Host" if gamer is host
                text += " (Host)";
            Vector2 stringCenter = font.MeasureString(text) / 2;
            
            Vector2 iconWidth = new Vector2(35, 0);
            Vector2 iconPosition = new Vector2(position.X - stringCenter.X - 35, position.Y - 25);

            // Draw the "is ready" icon.
            if (gamer.IsReady)
            {
                spriteBatch.Draw(isReadyTexture, iconPosition,
                                 FadeAlphaDuringTransition(Color.Lime));
            }

            iconPosition -= iconWidth;

            // Draw the "is muted", "is talking", or "has voice" icon.
            if (gamer.IsMutedByLocalUser)
            {
                spriteBatch.Draw(voiceMutedTexture, iconPosition,
                                 FadeAlphaDuringTransition(Color.Red));
            }
            else if (gamer.IsTalking)
            {
                spriteBatch.Draw(isTalkingTexture, iconPosition,
                                 FadeAlphaDuringTransition(Color.Yellow));
            }
            else if (gamer.HasVoice)
            {
                spriteBatch.Draw(hasVoiceTexture, iconPosition,
                                 FadeAlphaDuringTransition(Color.White));
            }

            // Draw the gamertag, normally in white, but yellow for local players.
            Color color = (gamer.IsLocal) ? Color.Yellow : Color.White;

            //spriteBatch.DrawString(font, text, position + iconWidth * 2, FadeAlphaDuringTransition(color));
            spriteBatch.DrawString(font, text, position, color, 0, stringCenter, 1, SpriteEffects.None, 0);
        }


        /// <summary>
        /// Helper modifies a color to fade its alpha value during screen transitions.
        /// </summary>
        Color FadeAlphaDuringTransition(Color color)
        {
            return new Color(color.R, color.G, color.B, TransitionAlpha);
        }


        #endregion
    }
}
